package com.zxy.supplier_system.server.configuration

import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.kotlin.readValue
import com.zxy.supplier_system.server.entity.Authority
import com.zxy.supplier_system.server.entity.Employee
import com.zxy.supplier_system.server.entity.EmployeeRole
import com.zxy.supplier_system.server.entity.Role
import com.zxy.supplier_system.server.repository.EmployeeRepository
import com.zxy.supplier_system.server.repository.RoleRepository
import com.zxy.supplier_system.server.repository.SystemServiceRepository
import com.zxy.supplier_system.server.utils.LoggerDelegate
import jakarta.annotation.PostConstruct
import jakarta.persistence.EntityManager
import jakarta.persistence.PersistenceContext
import org.apache.commons.lang3.RandomStringUtils
import org.springframework.stereotype.Component
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional

@Component
class DatabaseInitializer(
    val databaseInitializerHandler: DatabaseInitializerHandler
) {


    @PostConstruct
    @Transactional
    fun initData() {
        databaseInitializerHandler.hande()
    }

}


@Service
class DatabaseInitializerHandler(
    private val employeeRepository: EmployeeRepository,
    private val employeeProperties: EmployeeProperties,
    private val roleRepository: RoleRepository,
    private val systemService: SystemServiceRepository,
    @PersistenceContext
    private val entityManager: EntityManager,
    private val objectMapper: ObjectMapper,
) {
    companion object {
        private val log by LoggerDelegate()

        const val ROLE_SUPER_ADMIN_NAME = "超级管理员"
    }

    @Transactional
    fun hande() {
        removeNoExistsAuthorities()
        initializeEmployeeData()
    }

    private fun initializeEmployeeData() {
        val systemServices = systemService.findAll()
        systemServices.map { systemService ->
            val role = roleRepository.findByNameAndSystemService(ROLE_SUPER_ADMIN_NAME, systemService) ?: Role().apply {
                this.name = ROLE_SUPER_ADMIN_NAME
                this.systemService = systemService
            }
            this.roleRepository.saveAndFlush(role)
            role.authorities = Authority.values().toMutableList()
            employeeProperties.adminList.forEach {
                if (!this.employeeRepository.existsByPhoneNumberAndSystemService_Id(it.phoneNumber, systemService.id)) {
                    val randomAlphanumeric = RandomStringUtils.randomAlphanumeric(Employee.INITIAL_PASSWORD_LENGTH)
                    val employee = this.employeeRepository.save(Employee().apply {
                        this.name = it.name
                        this.phoneNumber = it.phoneNumber
                        this.password = randomAlphanumeric
                        this.systemService = systemService
                    })
                    employee.roles = mutableListOf(role).map { role ->
                        EmployeeRole().apply {
                            this.employee = employee
                            this.role = role
                        }
                    }.toMutableList()
                    this.employeeRepository.save(employee)
                    log.info("生成员账号，手机号：{} 密码：{}", it.phoneNumber, randomAlphanumeric)
                }
            }
            this.roleRepository.saveAndFlush(role)
        }
    }

    private fun removeNoExistsAuthorities() {
        val nativeQuery = entityManager.createNativeQuery("select role.id,role.authorities from role")
        val authorityNames = Authority.values().map {
            it.name
        }

        for (any in nativeQuery.resultList) {
            val array = any as Array<*>
            val authorities: MutableList<String> = objectMapper.readValue(array[1] as String)
            if (authorities.removeIf {
                    !authorityNames.contains(it)
                }) {
                roleRepository.updateRoleAuthorities(authorities.map { Authority.valueOf(it) }, array[0] as Int)
            }
        }
    }

}
